package com.superb.common.database.inner;

import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.superb.common.core.annotation.SuperbEncryptDecrypt;
import com.superb.common.core.annotation.SuperbEncryptDecryptField;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用于处理mapper查询加密字段模糊匹配效果
 * @Author: ajie
 * @CreateTime: 2024-05-11 17:46
 */
@Slf4j
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }),
})
@AllArgsConstructor
public class SuperbParamsInnerInterceptor implements InnerInterceptor {

    /**
     * 加密秘钥
     */
    private final String fieldEncryKey;

    /**
     * 执行查询sql前
     * @param executor
     * @param ms
     * @param parameter
     * @param rowBounds
     * @param resultHandler
     * @param boundSql
     * @throws SQLException
     */
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        List<ResultMap> resultMaps = ms.getResultMaps();
        Map<String, String> map = new HashMap<>();
        if (!resultMaps.isEmpty()) {
            Class<?> type = resultMaps.get(0).getType();
            if (type.isAnnotationPresent(SuperbEncryptDecrypt.class)) {
                Field[] fields = type.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(SuperbEncryptDecryptField.class)) {
                        String fieldCol = StringUtils.camelToUnderline(field.getName());
                        // 解密sql
                        map.put(fieldCol, "AES_DECRYPT(FROM_BASE64("+ fieldCol +"), '"+ fieldEncryKey +"')");
                    }
                }
            }
        }
        if (!map.isEmpty()) {
            if (parameter instanceof MapperMethod.ParamMap<?> paramMap) {
                if (paramMap.containsKey(Constants.WRAPPER)) {
                    String sql = boundSql.getSql();
                    int index = sql.indexOf(Constants.WHERE);
                    if (index != -1) {
                        String startSql = sql.substring(0, index);
                        String whereSql = sql.substring(index);
                        for (String key : map.keySet()) {
                            if (whereSql.contains(key)) {
                                whereSql = whereSql.replaceAll(key, map.get(key));
                            }
                        }
                        sql = startSql + whereSql;
                        PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
                        mpBoundSql.sql(sql);
                    }
                }
            }
        }
    }

}
